﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace Djs.Games.DeskGame.GameComponents
{
    /// <summary>
    /// Knihovna obrázků
    /// </summary>
    public class GameImageLibrary : IDisposable
    {
        #region Konstrukce, Dispose
        public GameImageLibrary()
        {
            this.ImageDict = new Dictionary<string, GameImageItem>();
            this.LoadImages();
        }
        void IDisposable.Dispose()
        {
            if (this.ImageDict != null)
            {
                foreach (GameImageItem ii in this.ImageDict.Values)
                {
                    ii.Dispose();
                }
                this.ImageDict = null;
            }
        }
        #endregion
        #region Image list Load
        /// <summary>
        /// Načte všechny obrázky z adresáře obrázků do zásobníku.
        /// Adresář obrázků = Aplikace/Pics.
        /// </summary>
        protected void LoadImages()
        {
            this.ImageDict.Clear();

            string appFile = Application.ExecutablePath;
            string appPath = System.IO.Path.GetDirectoryName(appFile);
            string picPath = System.IO.Path.Combine(appPath, "Pics");
            System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(picPath);
            if (!dir.Exists) return;
            
            System.IO.FileInfo[] files = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories);
            foreach (System.IO.FileInfo file in files)
            {
                string name = file.Name.ToLower();
                if (!this.ImageDict.ContainsKey(name))
                    this.ImageDict.Add(name, new GameImageItem(file.FullName));
            }
        }
        /// <summary>
        /// Zásobník obrázků. Klíčem je název obrázku včetně přípony, lower.
        /// </summary>
        protected Dictionary<string, GameImageItem> ImageDict;
        /// <summary>
        /// Třída obalující jeden obrázek.
        /// Realizuje lazy-loading obrázků až v případě jejich skutečné potřeby.
        /// </summary>
        protected class GameImageItem : IDisposable
        {
            public GameImageItem(string fileName)
            {
                this.FileName = fileName;
                this._Image = null;
            }
            /// <summary>
            /// Plný název souboru
            /// </summary>
            public string FileName { get; private set; }
            /// <summary>
            /// Obrázek
            /// </summary>
            public Image Image
            {
                get
                {
                    if (!this._ImageLoaded)
                    {   // Při prvním použití zkusím obrázek načíst ze souboru:
                        this._ImageLoaded = true;
                        try
                        {
                            this._Image = Image.FromFile(this.FileName);
                        }
                        catch
                        {
                            this._Image = null;
                        }
                    }
                    return this._Image;
                }
                set
                {
                    this._Image = value;
                    this._ImageLoaded = (value != null);
                }
            }
            private Image _Image;
            private bool _ImageLoaded;
            public void Dispose()
            {
                if (this._Image != null)
                {
                    this._Image.Dispose();
                    this._Image = null;
                }
            }
        }
        #endregion
        #region Image Get
        /// <summary>
        /// Počet položek v knihovně
        /// </summary>
        public int Count { get { return this.ImageDict.Count; } }
        /// <summary>
        /// Zjistí, zda existuje obrázek daného jména.
        /// </summary>
        /// <param name="imageName"></param>
        /// <returns></returns>
        public bool ContainImage(string imageName)
        {
            Image image;
            string imageKey = FileNameToKey(imageName);
            return this.TryGetImage(imageKey, out image);
        }
        /// <summary>
        /// Zkusí najít obrázek daného jména.
        /// Pokud najde, vrací true a obrázek uloží do out image.
        /// Pokud nenajde, vrací false.
        /// </summary>
        /// <param name="imageKey"></param>
        /// <param name="image"></param>
        /// <returns></returns>
        public bool TryGetImage(string imageName, out Image image)
        {
            image = null;
            GameImageItem ii;
            string imageKey = FileNameToKey(imageName);
            if (this.ImageDict.TryGetValue(imageKey, out ii))
                image = ii.Image;
            return (image != null);
        }
        public Image this[string imageName]
        {
            get
            {
                Image image;
                string imageKey = FileNameToKey(imageName);
                if (this.TryGetImage(imageKey, out image))
                    return image;
                return null;
            }
            set
            {
                string imageKey = FileNameToKey(imageName);
                if (!this.ImageDict.ContainsKey(imageKey))
                    this.ImageDict.Add(imageKey, new GameImageItem(imageKey));
                this.ImageDict[imageKey].Image = value;
            }
        }
        /// <summary>
        /// Vrací klíč obrázku z jeho jména souboru (tj. bez cesty, s příponou, lower, trim).
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string FileNameToKey(string fileName)
        {
            if (String.IsNullOrEmpty(fileName)) return "";
            string name = System.IO.Path.GetFileName(fileName);
            return name.ToLower().Trim();
        }
        #endregion

        public static ImageAttributes GetColorTransform()
        {
            return null;
        }

        public static void ColorToHSV(Color color, out double hue, out double saturation, out double value)
        {
            int max = Math.Max(color.R, Math.Max(color.G, color.B));
            int min = Math.Min(color.R, Math.Min(color.G, color.B));

            hue = color.GetHue();
            saturation = (max == 0) ? 0 : 1d - (1d * min / max);
            value = max / 255d;
        }

        public static Color ColorFromHSV(double hue, double saturation, double value)
        {
            int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
            double f = hue / 60 - Math.Floor(hue / 60);

            value = value * 255;
            int v = Convert.ToInt32(value);
            int p = Convert.ToInt32(value * (1 - saturation));
            int q = Convert.ToInt32(value * (1 - f * saturation));
            int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));

            if (hi == 0)
                return Color.FromArgb(255, v, t, p);
            else if (hi == 1)
                return Color.FromArgb(255, q, v, p);
            else if (hi == 2)
                return Color.FromArgb(255, p, v, t);
            else if (hi == 3)
                return Color.FromArgb(255, p, q, v);
            else if (hi == 4)
                return Color.FromArgb(255, t, p, v);
            else
                return Color.FromArgb(255, v, p, q);
        }
    }
    public struct ColorHSV
    {
        public float Hue;
        public float Saturation;
        public float Value;
    }
}
